package org.seamon.management.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.seamon.management.mapper.MenuMapper;
import org.seamon.management.pojo.dto.MenuInsertDto;
import org.seamon.management.pojo.dto.MenuUpdateDto;
import org.seamon.management.pojo.entity.Menu;
import org.seamon.management.pojo.entity.RoleMenu;
import org.seamon.management.pojo.vo.MenuTreeVo;
import org.seamon.management.service.MenuService;
import org.seamon.management.service.RoleMenuService;
import org.seamon.management.util.CacheConstants;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
* @author Simon
* @description 针对表【sys_menu(菜单权限表)】的数据库操作Service实现
* @createDate 2025-07-11 00:31:54
*/
@Slf4j
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu>
    implements MenuService{

    @Resource
    private RoleMenuService roleMenuService;

    private static List<MenuTreeVo> getMenuTreeVos(List<Menu> list) {
        // 转换成Vo
        List<MenuTreeVo> treeVos = list.stream()
                .map(menu -> {
                    MenuTreeVo menuTreeVO = new MenuTreeVo();
                    BeanUtils.copyProperties(menu, menuTreeVO);
                    return menuTreeVO;
                })
                .toList();

        // 构建映射
        Map<Long, MenuTreeVo> map = treeVos.stream()
                .collect(Collectors.toMap(MenuTreeVo::getId, Function.identity()));

        // 构建树结构
        List<MenuTreeVo> rootNodes = new ArrayList<>();

        treeVos.forEach(vo -> {
            MenuTreeVo parent = map.get(vo.getParentId());
            if (parent == null) {
                rootNodes.add(vo);
            } else {
                if (parent.getChildren() == null) {
                    parent.setChildren(new ArrayList<>());
                }
                parent.getChildren().add(vo);
            }
        });
        return rootNodes;
    }

    @Override
    @Cacheable(value = CacheConstants.MENU_TREE, key = "'listTree'")
    public List<MenuTreeVo> tree() {
        log.debug("获取菜单树");
        List<Menu> list = this.list();
        return getMenuTreeVos(list);
    }

    @Override
    @Cacheable(value = CacheConstants.MENU_TREE, key = "#roleId")
    public List<MenuTreeVo> tree(Long roleId) {
        log.debug("获取角色 {} 菜单树", roleId);
        log.debug("未获取缓存，从数据库查询");

        LambdaQueryWrapper<RoleMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RoleMenu::getRoleId, roleId);
        List<RoleMenu> roleMenus = roleMenuService.list(queryWrapper);
        List<Long> menuIds = roleMenus.stream()
                .map(RoleMenu::getMenuId)
                .distinct()
                .toList();
        if (menuIds.isEmpty()) {
            return new ArrayList<>();
        }
        List<Menu> list = this.listByIds(menuIds);
        return getMenuTreeVos(list);
    }

    @Override
    @CacheEvict(cacheNames = {CacheConstants.MENU_LIST, CacheConstants.MENU_TREE}, allEntries = true)
    public void save(MenuInsertDto dto) {
        Menu menu = new Menu();
        BeanUtils.copyProperties(dto, menu);
        this.save(menu);
    }

    @Override
    @CacheEvict(cacheNames = {CacheConstants.MENU_LIST, CacheConstants.MENU_TREE}, allEntries = true)
    public void update(MenuUpdateDto dto) {
        Menu menu = new Menu();
        BeanUtils.copyProperties(dto, menu);
        this.updateById(menu);
    }

    @Override
    @Cacheable(value = CacheConstants.MENU_PERMS, key = "#menuIds")
    public List<String> getPermsByIds(List<Long> menuIds) {
        return this.listByIds(menuIds).stream()
                .map(Menu::getPerms)
                .toList();
    }
}




